Creating and Organizing User-Defined Packages in Java
Course: Core Java Training
Topic: Creating and Organizing User-Defined Packages
Course Link: Core Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy
1. Introduction to User-Defined Packages
In Java, a package is a mechanism for grouping related classes, interfaces, enumerations, and other Java types. Packages help developers organize source code, avoid naming conflicts, control access, and maintain large applications more efficiently.
Java provides built-in packages such as java.lang, java.util, and java.io. Developers can also create their own packages according to an application's requirements. These are called user-defined packages.
For example, an application may contain separate packages for user management, product management, payment processing, and database operations. This separation makes the project easier to understand, test, and maintain.
Why Are User-Defined Packages Important?
- They group related classes and interfaces together.
- They prevent naming conflicts between types with the same simple name.
- They support access control through package-level visibility.
- They make code easier to reuse across different parts of an application.
- They encourage a clear, maintainable project structure.
- They help teams divide development work into logical modules.
2. What Is a Package in Java?
A package is a namespace that organizes related Java types. The package declaration identifies the package to which a source file's top-level types belong.
Consider these two classes:
package com.example.billing;
public class Invoice {
}
package com.example.inventory;
public class Invoice {
}
Both classes are named Invoice, but their fully qualified names are different:
com.example.billing.Invoice
com.example.inventory.Invoice
Because they belong to different packages, Java can distinguish between them.
3. Built-In Packages vs. User-Defined Packages
| Feature |
Built-In Packages |
User-Defined Packages |
| Meaning |
Packages supplied by the Java platform or libraries. |
Packages created by developers. |
| Examples |
java.util, java.io, java.time |
com.example.student, org.company.billing |
| Purpose |
Provide commonly used functionality. |
Organize application-specific code. |
| Creation |
Provided by Java libraries. |
Declared in source code using the package statement. |
| Maintenance |
Maintained by library developers. |
Maintained by the application team. |
4. Package Naming Conventions
Java package names are generally written in lowercase letters. A reverse-domain naming style is commonly used for projects to reduce the likelihood of naming conflicts.
Examples of Good Package Names
com.example.student
com.company.payments
org.training.corejava
in.justacademy.courses
Package Naming Best Practices
- Use lowercase names for consistency.
- Use meaningful words that describe the package's responsibility.
- Use reverse-domain naming when appropriate for your organization.
- Avoid spaces and hyphens in package names.
- Avoid using Java keywords as package-name components.
- Keep package names concise but descriptive.
For example, com.company.studentmanagement is more descriptive than com.company.stuff.
5. The Package Declaration Statement
The package statement declares the package for the top-level types in a Java source file. When used, it must appear before import statements and type declarations, apart from comments and annotations allowed by the Java grammar.
Syntax
package packageName;
Example
package com.example.student;
public class Student {
public void display() {
System.out.println("Student package example");
}
}
In this example, the Student class belongs to the com.example.student package.
Important: When a source file does not declare a package, its top-level types belong to the unnamed package. For maintainable applications, using named packages is generally recommended.
6. Creating a User-Defined Package Step by Step
Let's create a package named com.example.greetings containing a class that displays a welcome message.
Step 1: Create the Source File
Create a file named Welcome.java with the following code:
package com.example.greetings;
public class Welcome {
public void showMessage() {
System.out.println("Welcome to Java packages!");
}
}
Step 2: Save the File in the Matching Directory Structure
A conventional source layout mirrors the package name:
JavaProject/
└── src/
└── com/
└── example/
└── greetings/
└── Welcome.java
Here, the directory hierarchy com/example/greetings corresponds to the package com.example.greetings. Java compilers and build tools use package names and source or class paths to locate types.
Step 3: Compile the Package Class
From the JavaProject directory, run:
javac -d out src/com/example/greetings/Welcome.java
The -d out option tells the compiler to place generated class files in the out directory and create the required package subdirectories.
After compilation, the structure will look like this:
JavaProject/
├── src/
│ └── com/example/greetings/Welcome.java
└── out/
└── com/example/greetings/Welcome.class
Step 4: Create a Class That Uses the Package
Create Main.java inside the src directory:
import com.example.greetings.Welcome;
public class Main {
public static void main(String[] args) {
Welcome welcome = new Welcome();
welcome.showMessage();
}
}
Step 5: Compile and Run the Main Class
From the JavaProject directory, compile the main class with the compiled package classes on the classpath:
javac -cp out -d out src/Main.java
java -cp out Main
Output:
Welcome to Java packages!
The classpath option -cp out tells Java where to find compiled classes. The main class is run by its class name, Main, because it is in the unnamed package in this example.
7. Organizing Multiple Classes into a Package
A user-defined package can contain multiple related classes. For example, a student management application could contain Student, Course, and StudentService classes.
Example Project Structure
src/
└── com/
└── example/
└── student/
├── Student.java
├── Course.java
└── StudentService.java
Student.java
package com.example.student;
public class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
Course.java
package com.example.student;
public class Course {
private String courseName;
public Course(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
}
StudentService.java
package com.example.student;
public class StudentService {
public void displayStudent(Student student) {
System.out.println("Student ID: " + student.getId());
System.out.println("Student Name: " + student.getName());
}
}
All three classes belong to the same package. They can refer to one another by simple class name without importing each other, provided access rules permit it.
8. Importing Classes from User-Defined Packages
When a class in one package needs to use a public class from another package, it can use an import statement or the class's fully qualified name.
Import a Single Class
import com.example.student.Student;
Import All Accessible Types by Simple Name from a Package
import com.example.student.*;
The wildcard import makes accessible types in that package available by simple name. It does not import types from its subpackages, and it does not grant access to non-public types or members.
Complete Example
import com.example.student.Student;
import com.example.student.StudentService;
public class StudentApp {
public static void main(String[] args) {
Student student = new Student(101, "Aarav");
StudentService service = new StudentService();
service.displayStudent(student);
}
}
Possible output:
Student ID: 101
Student Name: Aarav
To compile this example, ensure the package classes and StudentApp.java are available on the appropriate source path or classpath. For a simple project with compiled classes in out, compile using javac -cp out -d out StudentApp.java from the directory containing the file, then run with java -cp out StudentApp.
9. Understanding Subpackages
A subpackage is a package whose name extends another package name. For example, com.example.student.service is a separate package from com.example.student.
Example Package Hierarchy
com.example
├── student
│ ├── Student.java
│ └── StudentRepository.java
├── course
│ └── Course.java
└── service
└── StudentService.java
Subpackages help organize larger projects into logical sections. However, Java does not automatically treat a subpackage as part of its parent package for access control. Classes in com.example.student and com.example.student.service belong to different packages.
10. Access Modifiers and Packages
Access modifiers determine where classes, fields, constructors, and methods can be accessed. Package organization works closely with Java access control.
| Modifier |
Same Class |
Same Package |
Subclass in Another Package |
Unrelated Class in Another Package |
public |
Yes |
Yes |
Yes, subject to normal access rules |
Yes |
protected |
Yes |
Yes |
Yes, through the applicable subclass access rules |
No |
| No modifier (package-private) |
Yes |
Yes |
No |
No |
private |
Yes |
No, except permitted access within the enclosing type's scope |
No |
No |
Example of Package-Private Access
Account.java:
package com.example.finance;
class Account {
void showBalance() {
System.out.println("Balance information");
}
}
In this example, the class Account has no public modifier. It is therefore accessible only within its package. A class in a different package cannot import and use it as a public type.
Best practice: Expose only the classes and members that other packages need. Keep implementation details package-private or private where appropriate.
11. Using Fully Qualified Class Names
A fully qualified class name contains the package name followed by the class name. It allows a class to be referenced without an import statement.
Example
public class Main {
public static void main(String[] args) {
com.example.greetings.Welcome welcome =
new com.example.greetings.Welcome();
welcome.showMessage();
}
}
This approach is useful when only a few references are needed or when two packages contain classes with the same simple name.
Resolving Name Conflicts
Suppose two packages contain a class named Report:
com.example.sales.Report
com.example.accounts.Report
Rather than importing both classes and using the ambiguous simple name, reference them with their fully qualified names:
com.example.sales.Report salesReport =
new com.example.sales.Report();
com.example.accounts.Report accountReport =
new com.example.accounts.Report();
12. Organizing Packages in a Real-World Application
As an application grows, grouping all classes in a single package can make maintenance difficult. A layered package structure separates responsibilities.
Example: Student Management System
StudentManagement/
└── src/
└── com/
└── example/
└── studentmanagement/
├── model/
│ └── Student.java
├── service/
│ └── StudentService.java
├── repository/
│ └── StudentRepository.java
├── controller/
│ └── StudentController.java
└── Main.java
| Package |
Responsibility |
Example Class |
model |
Represents application data and domain objects. |
Student |
service |
Contains business rules and application logic. |
StudentService |
repository |
Handles data storage and retrieval. |
StudentRepository |
controller |
Coordinates requests and application operations. |
StudentController |
| Root package |
Contains the application entry point or startup coordination. |
Main |
This structure is an example rather than a mandatory Java layout. Small applications may need fewer packages, while larger applications may use feature-based organization or additional layers.
13. Complete Practical Example
Let's build a small application with a user-defined package called com.example.calculator.
Step 1: Create Calculator.java
package com.example.calculator;
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int multiply(int a, int b) {
return a * b;
}
}
Step 2: Create CalculatorApp.java
Place this file outside the package directory, such as in the project's src directory, without a package declaration:
import com.example.calculator.Calculator;
public class CalculatorApp {
public static void main(String[] args) {
Calculator calculator = new Calculator();
int sum = calculator.add(10, 20);
int product = calculator.multiply(5, 4);
System.out.println("Sum: " + sum);
System.out.println("Product: " + product);
}
}
Step 3: Compile and Execute
Assuming the files are stored in the following locations:
src/
├── CalculatorApp.java
└── com/
└── example/
└── calculator/
└── Calculator.java
Run the following commands from the project directory:
javac -d out src/com/example/calculator/Calculator.java
javac -cp out -d out src/CalculatorApp.java
java -cp out CalculatorApp
Output:
Sum: 30
Product: 20
Explanation: The Calculator class belongs to the com.example.calculator package. The CalculatorApp class imports it and calls its public methods. The compiled classes are stored in the out directory, which is specified on the classpath when compiling and running.
14. Creating Packages in an IDE
Java IDEs such as IntelliJ IDEA, Eclipse, and NetBeans provide package creation tools. Although the interface differs, the general process is similar.
- Create or open a Java project.
- Locate the source folder, commonly named
src.
- Create a new package, such as
com.example.student.
- Create a Java class inside the package.
- Add the required package declaration if the IDE does not insert it automatically.
- Create other packages for separate responsibilities.
- Import public types when using them from another package.
- Build and run the application to verify that the package structure is correct.
Using an IDE can reduce typing errors and automatically update package declarations when classes are moved or renamed through supported refactoring operations.
15. Common Errors and Troubleshooting
| Error or Problem |
Possible Cause |
Solution |
package ... does not exist |
The compiler cannot find the requested package. |
Check the package declaration, source path, compilation output, and classpath. |
cannot find symbol |
A class or member name is incorrect or unavailable. |
Check spelling, imports, compilation order, and access permissions. |
class ... is not public |
A package-private class is being accessed from outside its package. |
Make the class public if external access is intended and appropriate. |
class ... is public, should be declared in a file named ... |
The filename does not match the public top-level class name. |
Rename the file to match the public class name. |
| Application cannot find the main class |
The classpath or main-class name is incorrect. |
Set the classpath to the compiled output directory and use the correct fully qualified main-class name. |
| Unexpected access error |
A field, constructor, method, or type has restricted visibility. |
Review the access modifier and package relationship. |
| Subpackage class is not found |
The parent package is assumed to include its subpackages automatically. |
Import the subpackage's type explicitly or use its fully qualified name. |
16. Best Practices for Creating and Organizing Packages
- Choose meaningful names: Use names that clearly describe a package's purpose.
- Follow lowercase naming: Prefer names such as
com.example.payment.
- Group related types: Keep classes together when they work toward a cohesive responsibility.
- Avoid oversized packages: Split unrelated responsibilities into separate packages when it improves clarity.
- Use appropriate access control: Keep implementation details private or package-private where possible.
- Import deliberately: Use clear imports and fully qualified names when resolving naming conflicts.
- Keep source structure consistent: In conventional file-based projects, align directory names with package names.
- Use build tools for larger projects: Maven and Gradle can manage source directories, compilation, dependencies, and packaging.
- Refactor carefully: When moving classes between packages, update imports and check package-level access.
- Document package responsibilities: Add package-level documentation where it helps explain a package's purpose.
17. Practice Exercises
- Create a package named
com.example.geometry and add a Circle class with a method that calculates the area.
- Create a package named
com.example.employee containing an Employee class with fields for employee ID and name.
- Create a second class outside the employee package and import the public
Employee class.
- Create two classes with the same simple name in different packages and use both with fully qualified names.
- Create a project with
model, service, and repository packages. Describe the responsibility of each package.
- Declare a class without a public modifier and test whether a class in a different package can access it.
- Compile a package with
javac -d out and run a main class using -cp out.
18. Interview Questions and Answers
Q1. What is a user-defined package in Java?
A user-defined package is a package created by a developer to organize related classes, interfaces, and other Java types.
Q2. How do you create a package in Java?
Use a package declaration at the beginning of the source file, such as package com.example.demo;, and compile the class using a suitable source path or output directory.
Q3. Why are package names usually written in lowercase?
Lowercase package names are a widely used convention that improves consistency and distinguishes package names from class names, which commonly begin with uppercase letters.
Q4. What is the purpose of the import statement?
An import statement allows an accessible type from another package to be referred to by its simple name in that source file. It does not copy the class or grant additional permissions.
Q5. What is a fully qualified class name?
It is the complete name of a class, including its package name, such as com.example.student.Student.
Q6. Can two packages contain classes with the same name?
Yes. For example, com.example.sales.Report and com.example.accounts.Report are distinct types.
Q7. Does importing a package import its subpackages?
No. Importing com.example.* does not import types from com.example.student. Each package must be referenced separately.
Q8. Can a class without a public modifier be used from another package?
A top-level class without a public modifier is package-private and cannot be accessed as a type from outside its package.
Q9. What does the -d option do when compiling Java code?
The -d option specifies the destination directory for generated class files. The compiler creates package directories beneath that destination as needed.
Q10. Why is package organization useful in large projects?
It separates responsibilities, reduces naming conflicts, supports access control, and makes the application easier to navigate, test, and maintain.
19. Quick Revision Checklist
- Understand the purpose of user-defined packages.
- Know how to declare a package with the
package keyword.
- Use meaningful, lowercase package names.
- Understand the relationship between package names and directory structures.
- Know how to compile classes using
javac -d.
- Import public classes from other packages when needed.
- Use fully qualified class names to resolve naming conflicts.
- Understand that subpackages are separate packages for access-control purposes.
- Choose access modifiers carefully.
- Check the classpath when compiling and running package-based applications.
20. Conclusion
Creating and organizing user-defined packages is an essential Java skill. Packages provide a structured way to group related types, reduce naming conflicts, manage visibility, and organize applications as they grow. By understanding package declarations, imports, directory structures, compilation commands, and access modifiers, developers can build Java projects that are easier to maintain and extend.
For further learning, explore the Core Java Training course, register for a course demo, or visit the JustAcademy website.